package com.qiantu.phone.bluetooth;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.util.Log;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.hjq.base.utils.Md5Util;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.XXPermissions;
import com.hjq.toast.ToastUtils;
import com.qiantu.phone.R;

import java.util.List;
import java.util.UUID;

import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;

public class BluetoothConfigNetwork {

    private static final String TAG = "BluetoothConfigNetwork";
    private static final String GATEWAY_NAME = "IoT_Gateway";
    private static final String MQTT_URL = true ? "mqtt://wy.thinkhome.com.cn:1883" : "mqtt://dev-core.thinkhome.com.cn:1883";
    private static String admin = "ThinkHomeWY@2021";
    public static final int REQUEST_OPEN_BLUETOOTH = 666;

    private XXPermissions xxPermissions;
    private Activity activity;
    private Handler mHandler = new Handler();
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothLeScanner mBLEScanner;
    private boolean mScanning;
    private MyBroadcastReceiver mBroadcastReceiver;
    private MyScanCallback mScanCallback;
    private MyLeScanCallback mLeScanCallback;
    //需要连接的设备
    private BluetoothDevice mBluetoothDevice;
    //定义Gatt实现类
    private BluetoothGatt mBluetoothGatt;
    private BluetoothGattCallback mGattCallback;
    //定义重连次数
    private int reConnectionNum = 0;
    //最多重连次数
    private int maxConnectionNum = 3;
    //定义需要进行通信的ServiceUUID
    private static final UUID mServiceUUID = UUID.fromString("0000ffff-0000-1000-8000-00805f9b34fb");
    //定义需要进行通信的CharacteristicUUID
    private static final UUID mCharacteristicUUID = UUID.fromString("00000001-0000-1000-8000-00805f9b34fb");
    private OnConfigListener mOnConfigListener;
    private int scanSeconds = 60;
    //0主网关  1副网关
    private int hostType;
    private int networkType;
    private String placeId;
    private String wifiSsid;
    private String wifiPassword;

    public BluetoothConfigNetwork(Activity activity) {
        this.activity = activity;
    }

    public void start() {
        mScanCallback = new MyScanCallback();
        mLeScanCallback = new MyLeScanCallback();
        //初始化ble设配器
        BluetoothManager manager = (BluetoothManager) activity.getApplication().getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = manager.getAdapter();
        //判断蓝牙是否开启，如果关闭则请求打开蓝牙
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            // 低版本android会静默打开蓝牙，高版本android会请求打开蓝牙
            openBluetooth();
            IntentFilter filter = new IntentFilter();
            filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
            mBroadcastReceiver = new MyBroadcastReceiver();
            activity.registerReceiver(mBroadcastReceiver, filter);
        } else {
            requestPermissions();
        }
    }

    private void openBluetooth() {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        activity.startActivityForResult(enableBtIntent, REQUEST_OPEN_BLUETOOTH);
    }

    private class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取蓝牙广播  本地蓝牙适配器的状态改变时触发
            String action = intent.getAction();
            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                //获取蓝牙广播中的蓝牙新状态
                int blueNewState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                //获取蓝牙广播中的蓝牙旧状态
                int blueOldState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                switch (blueNewState) {
                    //正在打开蓝牙
                    case BluetoothAdapter.STATE_TURNING_ON:
                        break;
                    //蓝牙已打开
                    case BluetoothAdapter.STATE_ON:
                        requestPermissions();
                        break;
                    //正在关闭蓝牙
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        break;
                    //蓝牙已关闭
                    case BluetoothAdapter.STATE_OFF:
                        break;
                }
            }
        }
    }

    ;

    private void requestPermissions() {
        if (xxPermissions == null) {
            xxPermissions = XXPermissions.with(activity);
        }
        xxPermissions.permission(Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION)
                .request(new OnPermissionCallback() {
                    @Override
                    public void onGranted(List<String> permissions, boolean all) {
                        if (all) {
                            startScan(); //开始扫描
                        }
                    }

                    @Override
                    public void onDenied(List<String> permissions, boolean never) {
                        ToastUtils.show(R.string.common_permission_fail_1);
                        activity.finish();
                    }

                });
    }

    private void startScan() {
        if (mOnConfigListener != null) {
            mOnConfigListener.onConfigNetworkStart();
        }
        //处于未扫描的状态
        if (!mScanning) {
            //android 5.0后
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //标记当前的为扫描状态
                mScanning = true;
                //获取5.0新添的扫描类
                if (mBLEScanner == null) {
                    //mBLEScanner是5.0新添加的扫描类，通过BluetoothAdapter实例获取。
                    mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
                }
                //开始扫描
                //创建ScanSettings的build对象用于设置参数
                ScanSettings.Builder builder = new ScanSettings.Builder()
                        //设置高功耗模式
                        .setScanMode(SCAN_MODE_LOW_LATENCY);
                //android 6.0添加设置回调类型、匹配模式等
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    //定义回调类型
                    builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                    //设置蓝牙LE扫描滤波器硬件匹配的匹配模式
                    builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY);
                }
                //芯片组支持批处理芯片上的扫描
                if (mBluetoothAdapter.isOffloadedScanBatchingSupported()) {
                    //设置蓝牙LE扫描的报告延迟的时间（以毫秒为单位）
                    //设置为0以立即通知结果
                    builder.setReportDelay(0L);
                }
                //mScanSettings是ScanSettings实例，mScanCallback是ScanCallback实例，后面进行讲解。
                mBLEScanner.startScan(null, builder.build(), mScanCallback);
            } else {
                //标记当前的为扫描状态
                mScanning = true;
                //5.0以下  开始扫描
                //mLeScanCallback是BluetoothAdapter.LeScanCallback实例
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            }
            if (mHandler == null) {
                mHandler = new Handler();
            }
            //设置结束扫描
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    stopScan();
                }
            }, scanSeconds * 1000);
        }
    }

    private void stopScan() {
        //标记当前的为未扫描状态
        mScanning = false;
        //停止扫描设备
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (mBLEScanner != null && mBluetoothAdapter.isEnabled()) {
                mBLEScanner.stopScan(mScanCallback);
            }
        } else {
            //5.0以下  停止扫描
            if (mBluetoothAdapter != null) {
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }
        }
    }

    //5.0以下
    private class MyLeScanCallback implements BluetoothAdapter.LeScanCallback {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            //对扫描到的设备进行操作。如：获取设备信息。
            if (GATEWAY_NAME.equals(device.getName()) && mBluetoothDevice != device) {
                if (mBluetoothDevice == null || !mBluetoothDevice.getAddress().equals(device.getAddress())) {
                    mBluetoothDevice = device;
                    connectGatt();
                    stopScan();
                }
            }
        }
    }

    private class MyScanCallback extends ScanCallback {

        //当一个蓝牙ble广播被发现时回调
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            //扫描类型有开始扫描时传入的ScanSettings相关
            //对扫描到的设备进行操作。如：获取设备信息。
            if (GATEWAY_NAME.equals(result.getDevice().getName())) {
                if (mBluetoothDevice == null || !mBluetoothDevice.getAddress().equals(result.getDevice().getAddress())) {
                    mBluetoothDevice = result.getDevice();
                    connectGatt();
                    stopScan();
                }
            }
        }

        //批量返回扫描结果
        //@param results 以前扫描到的扫描结果列表。
        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
        }

        //当扫描不能开启时回调
        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
            //扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED，表示app无法注册，无法开始扫描。
        }
    }

    private void connectGatt() {
        if (mBluetoothDevice == null) {
            return;
        }
        //创建Gatt回调
        if (mGattCallback == null) {
            mGattCallback = new MyBluetoothGattCallback();
        }
        //连接设备
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mBluetoothGatt = mBluetoothDevice.connectGatt(activity,
                    false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
        } else {
            mBluetoothGatt = mBluetoothDevice.connectGatt(activity, false, mGattCallback);
        }
    }

    //定义蓝牙Gatt回调类
    private class MyBluetoothGattCallback extends BluetoothGattCallback {
        //连接状态回调
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                //判断是否断开连接码
                mBluetoothGatt.close();
            }
            // status 用于返回操作是否成功,会返回异常码。
            // newState 返回连接状态，如BluetoothProfile#STATE_DISCONNECTED、BluetoothProfile#STATE_CONNECTED
            //操作成功的情况下
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //判断是否连接码
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    //设置接收数据长度，默认20
                    mBluetoothGatt.requestMtu(100);
                }
            } else {   //异常码
                //断开连接，返回连接失败回调
                mBluetoothGatt.disconnect();
                //重连次数不大于最大重连次数
                if (reConnectionNum < maxConnectionNum) {
                    //重连次数自增
                    reConnectionNum++;
                    //连接设备
                    connectGatt();
                }
//                else {
//                    if(mOnConfigListener != null){
//                        mOnConfigListener.onConfigNetworkError("连接蓝牙网关失败");
//                    }
//                }
            }
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
            if (BluetoothGatt.GATT_SUCCESS == status) {
                Log.i("lzx", "onMtuChanged success MTU = " + mtu);
                mBluetoothGatt.discoverServices();
            } else {
                Log.i("lzx", "onMtuChanged fail");
            }
        }

        //服务发现回调
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //获取指定uuid的service
                BluetoothGattService gattService = mBluetoothGatt.getService(mServiceUUID);
                //获取到特定的服务不为空
                if (gattService != null) {
                    //获取指定uuid的Characteristic
                    BluetoothGattCharacteristic notificationGattCharacteristic = gattService.getCharacteristic(mCharacteristicUUID);
                    //获取特定特征成功
                    if (notificationGattCharacteristic != null) {
                        //设置订阅notificationGattCharacteristic值改变的通知
                        boolean notificationResult = mBluetoothGatt.setCharacteristicNotification(notificationGattCharacteristic, true);
                        if (!notificationResult) {
                            Log.e(TAG, "设置订阅notificationGattCharacteristic值改变的通知失败");
                            return;
                        }
                        //获取其对应的通知Descriptor
                        BluetoothGattDescriptor descriptor = notificationGattCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
                        if (descriptor != null) {
                            //设置通知值
                            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                            boolean descriptorResult = mBluetoothGatt.writeDescriptor(descriptor);
                            if (!descriptorResult) {
                                Log.e(TAG, "BluetoothGattDescriptor设置通知值失败");
                                return;
                            }
                        }
                        //写入你需要传递给外设的特征值（即传递给外设的信息）
                        notificationGattCharacteristic.setValue(getData().getBytes());
                        //通过GATt实体类将，特征值写入到外设中。
                        mBluetoothGatt.writeCharacteristic(notificationGattCharacteristic);
                    }

                } else {
                    //获取特定服务失败
                    Log.e(TAG, "获取特定BluetoothGattService失败");
                    if (mOnConfigListener != null) {
                        mOnConfigListener.onConfigNetworkError("");
                    }
                }
            }
        }

        //特征写入回调
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //获取写入到外设的特征值
                Log.i("lzx", "onCharacteristicRead:" + new String(characteristic.getValue()));
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //获取读取到的特征值
                Log.i("lzx", "onCharacteristicRead:" + new String(characteristic.getValue()));
            }
        }

        //外设特征值改变回调
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            byte[] value = characteristic.getValue();
            if (value != null && value.length > 0) {
                String v = new String(value);
                //获取外设修改的特征值
                Log.i("lzx", "onCharacteristicChanged:" + v);
                JsonObject jsonObject = new JsonParser().parse(v).getAsJsonObject();
                int ret = jsonObject.get("ret").getAsInt();
                switch (ret) {
                    case 0:
                        //对特征值进行解析
                        mBluetoothGatt.disconnect();
                        if (mOnConfigListener != null) {
                            String sn = jsonObject.get("data").getAsJsonObject().get("sn").getAsString();
                            mOnConfigListener.onConfigNetworkSuccess(sn);
                        }
                        break;
                    case 101:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("没有发现Wi-Fi");
                        }
                        break;
                    case 102:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("Wi-Fi密码错误");
                        }
                        break;
                    case 103:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("无法连接Wi-Fi");
                        }
                        break;
                    case 104:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("以太网端口未连接");
                        }
                        break;
                    case 105:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("⽆法获取IP地址");
                        }
                        break;
                    case 106:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("⽹关已属于某个场所，请先恢复出⼚");
                        }
                        break;
                    case 107:
                        if (mOnConfigListener != null) {
                            mOnConfigListener.onConfigNetworkError("副⽹关注册失败");
                        }
                        break;
                }
            }
        }

        //描述写入回调
        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
        }
    }

    private String getData() {
        JsonObject params = new JsonObject();
        params.addProperty("seq", 111);
        JsonObject data = new JsonObject();
        data.addProperty("mode", hostType);
        data.addProperty("room", 12);//房间随便写，不是我们app的房间号
        data.addProperty("network", networkType);
        data.addProperty("manu", "ThinkHome");
        JsonObject place = new JsonObject();
        place.addProperty("id", placeId);
        place.addProperty("admin", admin);
        place.addProperty("name", "12345");
        data.add("place", place);
        JsonObject mqttCloud = new JsonObject();
        mqttCloud.addProperty("url", MQTT_URL);
        mqttCloud.addProperty("addr", placeId);
        mqttCloud.addProperty("username", placeId);
        mqttCloud.addProperty("password", Md5Util.getMD5ofStr(placeId + admin).substring(0, 16));
        data.add("mqttCloud", mqttCloud);
        JsonObject wifi = new JsonObject();
        wifi.addProperty("ssid", wifiSsid);
        wifi.addProperty("pwd", wifiPassword);
        data.add("wifi", wifi);
        params.add("data", data);
        return params.toString();
    }

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
    }

    public interface OnConfigListener {
        void onConfigNetworkStart();

        void onConfigNetworkSuccess(String sn);

        void onConfigNetworkError(String msg);
    }

    public void setOnConfigListener(OnConfigListener onConfigListener) {
        this.mOnConfigListener = onConfigListener;
    }

    public void setScanSeconds(int scanSeconds) {
        this.scanSeconds = scanSeconds;
    }

    public void setHostType(int hostType) {
        this.hostType = hostType;
    }

    public void setNetworkType(int networkType) {
        this.networkType = networkType;
    }

    public void setPlaceId(String placeId) {
        this.placeId = placeId;
    }

    public void setWifiSsid(String wifiSsid) {
        this.wifiSsid = wifiSsid;
    }

    public void setWifiPassword(String wifiPassword) {
        this.wifiPassword = wifiPassword;
    }

    public void stop() {
        reConnectionNum = 0;
        if (mBroadcastReceiver != null) {
            //防止多次stop，导致多次解绑异常
            try {
                activity.unregisterReceiver(mBroadcastReceiver);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
        }
        stopScan();
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
        }
        mBluetoothDevice = null;
    }
}
